package pers.chao.tool.thread.pool.impl;

import pers.chao.tool.thread.pool.IExecutor;

import java.util.concurrent.TimeUnit;

/**
 * Description: 配置好的线程池
 * <p>
 * 基础规则:
 * 当一个新任务在execute（Runnable）方法中提交，并且少于corePoolSize线程
 * 运行时，会创建一个新线程来处理请求，即使其他工作线程处于空闲状态。如果
 * 运行的线程超过corePoolSize但小于maximumPoolSize线程，新线程为
 * 创建来处理请求，但当它变成空闲时等待的间隔时间
 * 新任务超过keepAliveTime时，它将被终止，以降低资源成本。
 *
 * @author W.Chao
 * @date 2020/12/13 19:59
 **/
public final class ProposedThreadPool {
	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 当前任务入队列，直到有闲置线程可执行任务
	 *
	 * @param corePoolSize    线程池保存的活动最小线程数
	 * @param maximumPoolSize 最大线程数
	 * @param keepAliveTime
	 * @param unit
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newExceedWaitPool(int corePoolSize,
											  int maximumPoolSize, long keepAliveTime, TimeUnit unit,
											  String prefixName) {
		if (corePoolSize == 0) {
			return newNoCorePool(maximumPoolSize, keepAliveTime, unit, prefixName);
		}

		return new ThreadExecutor(new RealExecutors.ExceedWaitExecutor(corePoolSize, maximumPoolSize,
				keepAliveTime, unit, prefixName));
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 当前任务被丢弃
	 *
	 * @param corePoolSize    线程池保存的活动最小线程数
	 * @param maximumPoolSize 最大线程数
	 * @param keepAliveTime
	 * @param unit
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newExceedDiscardPool(int corePoolSize, int maximumPoolSize,
												 long keepAliveTime, TimeUnit unit,
												 String prefixName) {
		return new ThreadExecutor(new RealExecutors.
				ExceedDiscardExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, prefixName));
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 将使用当前的调用线程执行任务
	 *
	 * @param corePoolSize    线程池保存的活动最小线程数
	 * @param maximumPoolSize 最大线程数
	 * @param keepAliveTime
	 * @param unit
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newExceedCallerRunsPool(int corePoolSize, int maximumPoolSize,
													long keepAliveTime, TimeUnit unit,
													String prefixName) {
		return new ThreadExecutor(new RealExecutors.
				ExceedCallerRunsExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, prefixName));
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 将使用临时线程池执行任务
	 *
	 * @param corePoolSize    线程池保存的活动最小线程数
	 * @param maximumPoolSize 最大线程数
	 * @param keepAliveTime
	 * @param unit
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newExceedCallImmediatelyPool(int corePoolSize, int maximumPoolSize,
														 long keepAliveTime, TimeUnit unit,
														 String prefixName) {
		return new ThreadExecutor(new RealExecutors.
				ExceedCallImmediatelyExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, prefixName));
	}

	/**
	 * 单线程线程池
	 *
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newSinglePool(String prefixName) {
		return new ThreadExecutor(new RealExecutors.SinglePoolExecutor(prefixName));
	}

	/**
	 * 固定线程线程池
	 *
	 * @param threadCount
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newFixedPool(int threadCount, String prefixName) {
		return new ThreadExecutor(new RealExecutors.FixedPoolExecutor(threadCount, prefixName));
	}

	/**
	 * 无最大线程数量限制，超出核心线程数时，超出的线程数闲置时，超出keepAliveTime时间将会被回收
	 *
	 * @param keepAliveTime
	 * @param unit
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newCachedPool(long keepAliveTime, TimeUnit unit, String prefixName) {
		return new ThreadExecutor(new RealExecutors.CachedPoolExecutor(keepAliveTime, unit, prefixName));
	}

	/**
	 * 核心线程数和最大线程数相同，核心线程闲置超过保活时间还是会被回收
	 *
	 * @param threadCount
	 * @param keepAliveTime
	 * @param unit
	 * @param prefixName
	 * @return
	 */
	public static IExecutor newNoCorePool(int threadCount, long keepAliveTime, TimeUnit unit,
										  String prefixName) {
		return new ThreadExecutor(new RealExecutors.NoCoreExecutor(threadCount, keepAliveTime, unit,
				prefixName));
	}

	// ****************************
	// 理论线程池
	// ****************************

	public static IExecutor computedThreadPool(String prefixName) {
		int count = Runtime.getRuntime().availableProcessors() + 1;
		return newExceedWaitPool(count, count, 60L, TimeUnit.SECONDS, prefixName);
	}

	public static IExecutor computedThreadPool(String prefixName, long keepAliveTime) {
		int count = Runtime.getRuntime().availableProcessors() + 1;
		return newExceedWaitPool(count, count, keepAliveTime, TimeUnit.SECONDS, prefixName);
	}

	public static IExecutor ioThreadPool(String prefixName) {
		int count = 2 * Runtime.getRuntime().availableProcessors() + 1;
		return newExceedWaitPool(count, count, 60L, TimeUnit.SECONDS, prefixName);
	}

	public static IExecutor ioThreadPool(String prefixName, long keepAliveTime) {
		int count = 2 * Runtime.getRuntime().availableProcessors() + 1;
		return newExceedWaitPool(count, count, keepAliveTime, TimeUnit.SECONDS, prefixName);
	}

}
